// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//

#pragma once

#include <iosfwd>
#include <string>
#include <utility>
#include <turbo/utility/status.h>
#include <turbo/base/macros.h>

namespace nebula {

    class Array;

    class ChunkedArray;

    class RecordBatch;

    class Schema;

    class Table;

    /// \class PrettyPrintDelimiters
    /// \brief Options for controlling which delimiters to use when printing
    /// an Array or ChunkedArray.
    struct TURBO_EXPORT PrettyPrintDelimiters {
        /// Delimiter to use when opening an Array or ChunkedArray (e.g. "[")
        std::string open = "[";

        /// Delimiter to use when closing an Array or ChunkedArray (e.g. "]")
        std::string close = "]";

        /// Delimiter for separating individual elements of an Array (e.g. ","),
        /// or individual chunks of a ChunkedArray
        std::string element = ",";

        /// create a PrettyPrintDelimiters instance with default values
        static PrettyPrintDelimiters defaults() { return PrettyPrintDelimiters(); }
    };

    /// \class PrettyPrintOptions
    /// \brief Options for controlling how various Nebula types should be printed.
    struct TURBO_EXPORT PrettyPrintOptions {
        PrettyPrintOptions() = default;

        PrettyPrintOptions(int indent,  // NOLINT runtime/explicit
                           int window = 10, int indent_size = 2, std::string null_rep = "null",
                           bool skip_new_lines = false, bool truncate_metadata = true,
                           int container_window = 2)
                : indent(indent),
                  indent_size(indent_size),
                  window(window),
                  container_window(container_window),
                  null_rep(std::move(null_rep)),
                  skip_new_lines(skip_new_lines),
                  truncate_metadata(truncate_metadata) {}

        /// create a PrettyPrintOptions instance with default values
        static PrettyPrintOptions defaults() { return PrettyPrintOptions(); }

        /// Number of spaces to shift entire formatted object to the right
        int indent = 0;

        /// Size of internal indents
        int indent_size = 2;

        /// Maximum number of elements to show at the beginning and at the end.
        int window = 10;

        /// Maximum number of elements to show at the beginning and at the end, for elements
        /// that are containers (that is, list in ListArray and chunks in ChunkedArray)
        int container_window = 2;

        /// String to use for representing a null value, defaults to "null"
        std::string null_rep = "null";

        /// Skip new lines between elements, defaults to false
        bool skip_new_lines = false;

        /// Limit display of each KeyValueMetadata key/value pair to a single line at
        /// 80 character width
        bool truncate_metadata = true;

        /// If true, display field metadata when pretty-printing a Schema
        bool show_field_metadata = true;

        /// If true, display schema metadata when pretty-printing a Schema
        bool show_schema_metadata = true;

        /// Delimiters to use when printing an Array
        PrettyPrintDelimiters array_delimiters = PrettyPrintDelimiters::defaults();

        /// Delimiters to use when printing a ChunkedArray
        PrettyPrintDelimiters chunked_array_delimiters = PrettyPrintDelimiters::defaults();
    };

    /// \brief Print human-readable representation of RecordBatch
    TURBO_EXPORT
    turbo::Status pretty_print(const RecordBatch &batch, int indent, std::ostream *sink);

    TURBO_EXPORT
    turbo::Status pretty_print(const RecordBatch &batch, const PrettyPrintOptions &options,
                              std::ostream *sink);

    /// \brief Print human-readable representation of Table
    TURBO_EXPORT
    turbo::Status pretty_print(const Table &table, const PrettyPrintOptions &options,
                              std::ostream *sink);

    /// \brief Print human-readable representation of Array
    TURBO_EXPORT
    turbo::Status pretty_print(const Array &arr, int indent, std::ostream *sink);

    /// \brief Print human-readable representation of Array
    TURBO_EXPORT
    turbo::Status pretty_print(const Array &arr, const PrettyPrintOptions &options,
                              std::ostream *sink);

    /// \brief Print human-readable representation of Array
    TURBO_EXPORT
    turbo::Status pretty_print(const Array &arr, const PrettyPrintOptions &options,
                              std::string *result);

    /// \brief Print human-readable representation of ChunkedArray
    TURBO_EXPORT
    turbo::Status pretty_print(const ChunkedArray &chunked_arr, const PrettyPrintOptions &options,
                              std::ostream *sink);

    /// \brief Print human-readable representation of ChunkedArray
    TURBO_EXPORT
    turbo::Status pretty_print(const ChunkedArray &chunked_arr, const PrettyPrintOptions &options,
                              std::string *result);

    TURBO_EXPORT
    turbo::Status pretty_print(const Schema &schema, const PrettyPrintOptions &options,
                              std::ostream *sink);

    TURBO_EXPORT
    turbo::Status pretty_print(const Schema &schema, const PrettyPrintOptions &options,
                              std::string *result);

    TURBO_EXPORT
    turbo::Status DebugPrint(const Array &arr, int indent);

}  // namespace nebula
